这是一节动手课:每个任务都先自己写、自己跑,跑不出来再看提示,最后对参考答案。先扫一眼速查区,然后从环境准备开始 —— 这一步没做好,后面代码会连不上。👇
📌 动手前 · 30 秒速查
import mysql.connector # ① 导入 db = mysql.connector.connect(...) # ② 连接 cursor = db.cursor() # ③ 游标 try: cursor.execute("...") # ④ 执行 db.commit() # 改数据要 commit except: db.rollback() cursor.close(); db.close() # ⑤ 关闭
最容易丢分的三个坑
commit,数据只在缓冲区,关掉就没了。fetchone 给元组、fetchall 给列表,别拿错。环境准备:把"能连上"先搞定
🛠️ 第一步:装连接包
在命令行(不是 Python 里)运行下面这句。装完再用一行验证它能导入。
# 安装
pip install mysql-connector-python
# 验证:能打印出版本号就说明装好了
python -c "import mysql.connector; print(mysql.connector.__version__)"
🛠️ 第二步:建库、建表、灌数据
打开 Navicat / 命令行 / Workbench,把下面整段复制运行。所有任务都用这套 teaching 库里的 s 表。
-- 1. 建库并使用(讲义里的 connect 也连这个库)
CREATE DATABASE IF NOT EXISTS teaching DEFAULT CHARSET utf8mb4;
USE teaching;
-- 2. 重建学生表(先删后建,方便反复练习)
DROP TABLE IF EXISTS s;
CREATE TABLE s (
sno CHAR(5) PRIMARY KEY, -- 学号
sn VARCHAR(10) NOT NULL, -- 姓名
sex CHAR(2), -- 性别
age INT, -- 年龄
maj VARCHAR(30), -- 专业
dept VARCHAR(30) -- 院系
);
-- 3. 灌入 10 条测试数据(男女、年龄、院系都有,方便后面各种查询)
INSERT INTO s VALUES
('s1', '王彤', '女', 18, '计算机', '信息学院'),
('s2', '苏乐', '女', 20, '信息', '信息学院'),
('s3', '陶然', '男', 19, '计算机', '信息学院'),
('s4', '何欣荣','女', 21, '软件', '信息学院'),
('s5', '赵琳琳','女', 20, '数学', '理学院'),
('s6', '林毅', '男', 22, '信息', '信息学院'),
('s7', '周杰', '男', 18, '物理', '理学院'),
('s8', '郑爽', '女', 19, '数学', '理学院'),
('s9', '孙俊', '男', 21, '软件', '信息学院'),
('s10','苏红霞','女', 20, '信息', '信息学院');
🛠️ 第三步:跑一个连接测试脚本
新建一个 connect_test.py,把下面代码贴进去运行。能打印出版本和学生人数,就说明 Python 和 MySQL 接通了,可以开始做任务了。
import mysql.connector
db = mysql.connector.connect(
host='localhost',
user='root',
passwd='123456', # ← 改成你自己的 MySQL 密码
database='teaching'
)
cursor = db.cursor()
cursor.execute("SELECT VERSION()")
print("数据库版本:", cursor.fetchone()[0])
cursor.execute("SELECT COUNT(*) FROM s")
print("学生人数:", cursor.fetchone()[0])
cursor.close()
db.close()
① passwd 写的不是你本机 MySQL 的真实密码;② MySQL 服务没启动。
报 OperationalError 基本就是这俩之一,先检查它们。
命令行能打印 connector 版本号;MySQL 里 SELECT * FROM s; 看到 10 个学生;connect_test.py 打印出版本和人数 10。三项都对,开始动手。
实验一 · 基础任务
写一个程序,连上 teaching 数据库,查询学生总数并打印。这一关只为把 5 步流程跑通。
💡 卡住了?看这一条提示
① SQL 用 SELECT COUNT(*) FROM s。
② 结果只有一行一个数,用 fetchone() 取。
③ 它返回的是元组 (10,),要用 [0] 取出数字。查询不用 commit。
运行你的 .py,控制台应打印:
参考答案
import mysql.connector
db = mysql.connector.connect(
host='localhost', user='root',
passwd='123456', database='teaching'
)
cursor = db.cursor()
cursor.execute("SELECT COUNT(*) FROM s")
result = cursor.fetchone() # 返回元组,如 (10,)
print("学生总数:", result[0])
cursor.close()
db.close()
查询只是读,没有 commit;fetchone()[0] 把元组里的数字取出来。
用 try-except 模板向 s 表插入一名新学生,提交后到 MySQL 里确认真的插进去了。
('s20', '陈小明', '男', 20, '软件', '信息学院')
💡 卡住了?看这一条提示
① 这是"改数据",套速查区那个 try-except 壳。
② try 里:execute(插入SQL) + db.commit()。
③ except 里:db.rollback()。
① 程序打印"插入成功";② 回到 MySQL 执行下面这句,能查到 s20:
SELECT * FROM s WHERE sno='s20';
这一步能让你一辈子记住为什么要 commit:
① 先把 db.commit() 那行注释掉(前面加 #),改插一个新学号 's21',运行 —— 不会报错;
② 去 MySQL 查 SELECT * FROM s WHERE sno='s21'; —— 查不到!因为没提交;
③ 把注释去掉再跑一次,再查 —— 出现了。这就是"读不 commit,写必 commit"。
参考答案
import mysql.connector
db = mysql.connector.connect(
host='localhost', user='root',
passwd='123456', database='teaching'
)
cursor = db.cursor()
try:
cursor.execute("INSERT INTO s VALUES('s20','陈小明','男',20,'软件','信息学院')")
db.commit() # ⭐ 必须提交,数据才真的写入
print("插入成功")
except Exception as e:
db.rollback() # 出错就撤销
print("插入失败:", e)
cursor.close()
db.close()
"改数据"的黄金套路:try 里 execute + commit,except 里 rollback。
实验二 · 提高任务
把 s 表里所有"信息学院"学生的年龄都 +1,并打印影响了多少行。
💡 卡住了?看这一条提示
① SQL:UPDATE s SET age = age + 1 WHERE dept = '信息学院'。
② 改数据,记得 commit + try-except。
③ 执行后看 cursor.rowcount,就是被改的行数。
原始数据里信息学院有 7 人(s1、s2、s3、s4、s6、s9、s10),所以:
💡 注意:这条会真的改库。想恢复原样,重跑一遍环境准备第二步即可。
参考答案
import mysql.connector
db = mysql.connector.connect(
host='localhost', user='root',
passwd='123456', database='teaching'
)
cursor = db.cursor()
sql = "UPDATE s SET age = age + 1 WHERE dept = '信息学院'"
try:
cursor.execute(sql)
db.commit()
print("成功更新", cursor.rowcount, "行")
except Exception as e:
db.rollback()
print("更新失败:", e)
cursor.close()
db.close()
cursor.rowcount 返回上一次 execute 影响的行数,改 / 删时用它判断"到底动了几条"。
查询 s 表里所有女生的学号和姓名,一行行打印,格式为 s1 | 王彤。
💡 卡住了?看这一条提示
① SQL:SELECT sno, sn FROM s WHERE sex = '女'。
② 用 fetchall() 取全部,得到一个列表。
③ for row in results: 里,row[0] 是学号、row[1] 是姓名。
参考答案
import mysql.connector
db = mysql.connector.connect(
host='localhost', user='root',
passwd='123456', database='teaching'
)
cursor = db.cursor()
cursor.execute("SELECT sno, sn FROM s WHERE sex = '女'")
results = cursor.fetchall() # 列表,每个元素是一行的元组
for row in results:
print(row[0], "|", row[1])
cursor.close()
db.close()
也可以更优雅地解包:for sno, sn in results: print(sno, "|", sn)。
fetchall() 分别换成 fetchone() 和 fetchmany(3),各跑一次,看看打印出来有什么不同 —— 你会直观感受到:一个给"一行",一个给"全部列表",一个给"前 3 行的列表"。
实验三 · 拓展任务
写一个完整程序,在一次连接里依次完成下面几件事:
('s30','王晓明','男',20,'计算机','信息学院');② 修改"赵琳琳"的专业为"软件";
③ 上面两步用 try-except 包住,出错回滚;
④ 查询并逐行打印所有"信息学院"的学生;
⑤ 最后关闭游标和连接。
💡 卡住了?看这一条提示
① 一次连接做三件事:INSERT、UPDATE 是"改",SELECT 是"查"。
② 把 INSERT + UPDATE 放进同一个 try,一起 commit —— 保证两步要么都成、要么都退。
③ SELECT 单独放在 try 外面,查询不需要事务保护。
参考答案
import mysql.connector
# ① 连接
db = mysql.connector.connect(
host='localhost', user='root',
passwd='123456', database='teaching'
)
cursor = db.cursor()
# ② 改数据:INSERT + UPDATE 一起,用 try-except 保证原子性
try:
cursor.execute("INSERT INTO s VALUES('s30','王晓明','男',20,'计算机','信息学院')")
cursor.execute("UPDATE s SET maj='软件' WHERE sn='赵琳琳'")
db.commit()
print("插入和修改成功!")
except Exception as e:
db.rollback()
print("操作失败,已回滚:", e)
# ③ 查数据:单独执行,不需要事务
print("\n--- 信息学院学生列表 ---")
cursor.execute("SELECT * FROM s WHERE dept = '信息学院'")
for row in cursor.fetchall():
print(row)
# ④ 关闭
cursor.close()
db.close()
print("\n程序执行完毕")
要点:改放 try 里一起 commit(原子性)、查放 try 外、最后别忘 close()。
完成检查
完成进度:0 / 6
回顾今天真正动手做出来的:5 步连上库、带 try-except 的增 / 改、commit 的作用、用 fetch 把查询打印出来。这几样,就是"用 Python 操作数据库"的全部要点。整门课到这里也圆满了 👏。